package com.redepronik.negosys.invfac.service;

import static com.redepronik.negosys.utils.Utils.divide;
import static com.redepronik.negosys.utils.Utils.newBigDecimal;
import static com.redepronik.negosys.utils.Utils.presentaMensaje;
import static com.redepronik.negosys.utils.Utils.redondear;
import static com.redepronik.negosys.utils.Utils.timestamp;
import static com.redepronik.negosys.utils.Utils.valorConIva;
import static com.redepronik.negosys.utils.Utils.valorConPorcentaje;

import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import net.sourceforge.barbecue.BarcodeFactory;
import net.sourceforge.barbecue.BarcodeImageHandler;

import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.redepronik.negosys.invfac.dao.ProductoDao;
import com.redepronik.negosys.invfac.entity.Bodega;
import com.redepronik.negosys.invfac.entity.Estadokardex;
import com.redepronik.negosys.invfac.entity.Iva;
import com.redepronik.negosys.invfac.entity.Kardex;
import com.redepronik.negosys.invfac.entity.Producto;
import com.redepronik.negosys.invfac.entity.Productocaracteristica;
import com.redepronik.negosys.invfac.entity.Productounidad;
import com.redepronik.negosys.invfac.entity.TipoPrecioProducto;
import com.redepronik.negosys.invfac.entityAux.BodegaProducto;
import com.redepronik.negosys.invfac.entityAux.ControlInventarioReporte;
import com.redepronik.negosys.invfac.entityAux.TablaPrecios;

@Service
public class ProductoServiceImpl implements ProductoService {

	@Autowired
	private ProductoDao productoDao;

	@Autowired
	private KardexService kardexService;

	@Autowired
	private BodegaService bodegaService;

	@Autowired
	private IvaService ivaService;

	private Iva iva;

	private ValidatorFactory factory = Validation
			.buildDefaultValidatorFactory();
	private Validator validator = factory.getValidator();

	public void actualizar(Producto producto,
			List<TablaPrecios> listaPrecioProductos) {
		Set<ConstraintViolation<Producto>> violationsProducto = validator
				.validate(producto);

		if (violationsProducto.size() > 0)
			for (ConstraintViolation<Producto> cv : violationsProducto)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
		else if (comprobarUnidadesVacias(producto))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE UNIDADES VACIAS O CON VALOR CERO");
		else if (producto.getGrupo().getGrupoid() == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO, "ESCOJA UN GRUPO");
		else if (comprobarCaracteristicasVacias(producto))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"INGRESE UN VALOR EN UNA DE LAS CARACTERISTICAS IMPRIMIBLES");
		else if (comprobarPreciosVacias(listaPrecioProductos))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE TIPOS DE PRECIOS VACIOS O NO A ESCOGIDO EL PVP");
		else {
			producto.setTipoPrecioProductos(new ArrayList<TipoPrecioProducto>());
			for (TablaPrecios tablaPrecios : listaPrecioProductos)
				if (tablaPrecios.getTipoPrecioProducto()
						.getPorcentajepreciofijo()) {
					tablaPrecios.getTipoPrecioProducto().setValor(
							tablaPrecios.getPorcentaje());
					producto.addTipoPrecioProducto(tablaPrecios
							.getTipoPrecioProducto());
				} else {
					tablaPrecios.getTipoPrecioProducto().setValor(
							tablaPrecios.getPrecio());
					producto.addTipoPrecioProducto(tablaPrecios
							.getTipoPrecioProducto());
				}

			int c = 1;
			for (Productounidad pu : producto.getProductounidads())
				pu.setOrden(c++);

			c = 1;
			for (TipoPrecioProducto tp : producto.getTipoPrecioProductos()) {
				tp.setOrden(c++);
			}
			productoDao.actualizar(nombre(producto));
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE ACTUALIZÓ EL PRODUCTO CORRECTAMENTE", "error", true);
		}
	}

	public void actualizarKardexInicial(Producto producto, Bodega bodega,
			Integer cantidad) {

		Estadokardex estadoKardex = new Estadokardex();
		estadoKardex.setEstadokardexid(1);

		Kardex kardex = new Kardex();
		kardex.setEstadokardex(estadoKardex);
		kardex.setNota("");
		kardex.setFecha(timestamp());
		kardex.setCantidad(cantidad);
		kardex.setPrecio(producto.getPrecio());

		productoDao.actualizar(producto);
		kardexService.insertar(kardex);
	}

	public BigDecimal calcularPrecio(Producto producto, int bodegaId,
			int precioId) {
		Kardex k = kardexService
				.obtenerSaldoActual(producto.getEan(), bodegaId);
		if (k != null) {
			for (TipoPrecioProducto tipoPrecioProducto : producto
					.getTipoPrecioProductos())
				if (tipoPrecioProducto.getTipoprecioproductoid().compareTo(
						precioId) == 0)
					return tipoPrecioProducto.getPorcentajepreciofijo() ? redondear(valorConPorcentaje(
							k.getPrecio(), tipoPrecioProducto.getValor()))
							: tipoPrecioProducto.getValor();
		}
		return newBigDecimal();
	}

	public BigDecimal calcularPrecio(Producto producto, int precioId) {
		for (TipoPrecioProducto tipoPrecioProducto : producto
				.getTipoPrecioProductos())
			if (tipoPrecioProducto.getTipoprecioproductoid()
					.compareTo(precioId) == 0)
				return tipoPrecioProducto.getPorcentajepreciofijo() ? redondear(valorConPorcentaje(
						producto.getPrecio(), tipoPrecioProducto.getValor()))
						: tipoPrecioProducto.getValor();
		return newBigDecimal();
	}

	public void calcularPrecioPorGanancia(Producto producto,
			TablaPrecios tablaPrecios) {
		iva = ivaService.obtenerPorFecha(new Date());
		BigDecimal porcentajeOriginal = tablaPrecios.getPorcentaje();
		BigDecimal precioConIva = tablaPrecios.getPrecio().multiply(
				divide(iva.getPorcentaje(), "100").add(new BigDecimal("1.00")));
		BigDecimal porcentaje = divide(
				tablaPrecios.getPrecio().subtract(producto.getPrecio())
						.multiply(new BigDecimal("100.00")),
				producto.getPrecio());
		if (porcentaje.compareTo(newBigDecimal()) > 0) {
			tablaPrecios.setPrecioIva(precioConIva);
			tablaPrecios.setPorcentaje(porcentaje);
			tablaPrecios.setPrecio(redondear(tablaPrecios.getPrecio()));
		} else {
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE UN PRECIO > AL PRECIO COSTO");
			tablaPrecios.setPrecio(redondear(valorConPorcentaje(
					producto.getPrecio(), porcentajeOriginal)));
		}
	}

	public void calcularPrecioPorIva(Producto producto,
			TablaPrecios tablaPrecios) {
		iva = ivaService.obtenerPorFecha(new Date());
		BigDecimal precioSinIvaOriginal = tablaPrecios.getPrecio();
		BigDecimal precioSinIva = divide(tablaPrecios.getPrecioIva(),
				divide(iva.getPorcentaje(), "100").add(new BigDecimal("1.00")));
		BigDecimal porcentaje = divide(
				precioSinIva.subtract(producto.getPrecio()).multiply(
						new BigDecimal("100.00")), producto.getPrecio());
		if (porcentaje.compareTo(newBigDecimal()) > 0) {
			tablaPrecios.setPrecio(precioSinIva);
			tablaPrecios.setPorcentaje(porcentaje);
			tablaPrecios.setPrecioIva(redondear(tablaPrecios.getPrecioIva()));
		} else {
			tablaPrecios.setPrecioIva(valorConIva(precioSinIvaOriginal));
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE UN PRECIO > AL PRECIO COSTO + IVA");
		}
	}

	public void calcularPrecioPorPorcentaje(Producto producto,
			TablaPrecios tablaPrecios) {
		BigDecimal precioSinIva = redondear(valorConPorcentaje(
				producto.getPrecio(), tablaPrecios.getPorcentaje()));
		BigDecimal precioConIva = valorConIva(precioSinIva);
		tablaPrecios.setPrecio(precioSinIva);
		tablaPrecios.setPrecioIva(precioConIva);
		tablaPrecios.setPorcentaje(redondear(tablaPrecios.getPorcentaje()));
	}

	public List<TablaPrecios> calcularPrecios(Producto producto,
			List<TablaPrecios> listaPrecios) {
		if (producto.getPrecio() != null && listaPrecios != null
				&& !listaPrecios.isEmpty()) {
			for (TablaPrecios tablaPrecios : listaPrecios) {
				// dejar este println por que de lo contrario no hace el calculo
				System.out.println("-"
						+ tablaPrecios.getTipoPrecioProducto()
								.getPorcentajepreciofijo());
				if (tablaPrecios.getTipoPrecioProducto()
						.getPorcentajepreciofijo()) {
					if (tablaPrecios.getPorcentaje() == null)
						tablaPrecios.setPorcentaje(tablaPrecios
								.getTipoPrecioProducto().getValor());
					BigDecimal precioSinIva = redondear(valorConPorcentaje(
							producto.getPrecio(), tablaPrecios.getPorcentaje()));
					BigDecimal precioConIva = valorConIva(precioSinIva);
					tablaPrecios.setPrecio(precioSinIva);
					tablaPrecios.setPrecioIva(precioConIva);
					tablaPrecios.setPorcentaje(redondear(tablaPrecios
							.getPorcentaje()));
				} else {
					if (tablaPrecios.getPrecio() == null)
						tablaPrecios.setPrecio(tablaPrecios
								.getTipoPrecioProducto().getValor());
					BigDecimal precioSinIva = redondear(tablaPrecios
							.getPrecio());
					BigDecimal precioConIva = valorConIva(precioSinIva);
					BigDecimal porcentaje = divide(
							precioSinIva.subtract(producto.getPrecio())
									.multiply(new BigDecimal("100.00")),
							producto.getPrecio());
					if (porcentaje.compareTo(new BigDecimal("0")) >= 0) {
						tablaPrecios.setPrecio(precioSinIva);
						tablaPrecios.setPrecioIva(precioConIva);
						tablaPrecios.setPorcentaje(porcentaje);
					} else {
						porcentaje = new BigDecimal("0");
						precioSinIva = redondear(valorConPorcentaje(
								producto.getPrecio(), porcentaje));
						precioConIva = valorConIva(precioSinIva);
						tablaPrecios.setPrecio(precioSinIva);
						tablaPrecios.setPrecioIva(precioConIva);
						tablaPrecios.setPorcentaje(redondear(porcentaje));
					}
				}
			}
		}
		return listaPrecios;
	}

	public boolean comprobarCaracteristicasVacias(Producto producto) {
		for (Productocaracteristica pc : producto.getProductocaracteristicas()) {
			if (pc.getImprimir() == true && pc.getValor() != null
					&& pc.getValor().length() == 0)
				return true;
		}
		return false;
	}

	public Boolean comprobarDatos(String campo, String valor, String id) {
		if (productoDao.comprobarIndices(Producto.class, campo, valor, id))
			return true;
		else
			return false;
	}

	public boolean comprobarPreciosVacias(
			List<TablaPrecios> listaPrecioProductos) {
		for (TablaPrecios tp : listaPrecioProductos)
			if (tp.getTipoPrecioProducto().getNombre() == null
					|| tp.getTipoPrecioProducto().getNombre().compareTo("") == 0)
				return true;

		boolean bn = true;
		for (TablaPrecios tp : listaPrecioProductos)
			if (tp.getTipoPrecioProducto().getPvp()) {
				bn = false;
				break;
			}

		if (bn)
			return true;
		else
			return false;
	}

	public boolean comprobarUnidadesVacias(Producto producto) {
		for (Productounidad pu : producto.getProductounidads())
			if (pu.getUnidad() != null
					&& (pu.getUnidad().getNombre() == null || pu.getUnidad()
							.getNombre().compareTo("") == 0)
					|| pu.getCantidad() == 0)
				return true;
		return false;
	}

	public Long contar() {
		return (Long) productoDao.contar(Producto.class, "productoid");
	}

	public String convertirUnidadString(int cantidad, List<Productounidad> list) {
		String nombre = "";
		for (int i = list.size() - 1; i >= 0; i--) {
			int unidad;
			if (i - 1 > 0)
				unidad = list.get(i).getCantidad()
						* list.get(i - 1).getCantidad();
			else
				unidad = list.get(i).getCantidad();

			if (cantidad >= unidad) {
				nombre = nombre + (nombre.compareTo("") == 0 ? " " : " - ")
						+ cantidad / unidad + " "
						+ list.get(i).getUnidad().getAbreviatura() + " ";
				cantidad = cantidad % unidad;
			}
		}

		return nombre;
	}

	public void eliminar(Producto producto) {
		producto.setActivo(producto.getActivo() ? false : true);
		productoDao.actualizar(producto);
		if (producto.getActivo())
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE ACTIVÓ EL PRODUCTO " + producto.getNombreimprimir());
		else
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE DESACTIVÓ EL PRODUCTO " + producto.getNombreimprimir());
	}

	public void eliminarTipoPrecioProducto(TablaPrecios tablaPrecios,
			List<TablaPrecios> listaPrecioProductos) {
		if (tablaPrecios.getTipoPrecioProducto().getPvp() == true)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"NO SE PUEDE ELIMINAR SI ES PVP");
		else {
			listaPrecioProductos.remove(tablaPrecios);
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"EL TIPO DE PRECIO FUE ELIMINADO");
		}
	}

	public void eliminarUnidad(Producto producto, Productounidad productoUnidad) {
		if (producto.getProductounidads().size() > 1) {
			String unidad = null;
			if (productoUnidad.getUnidad() != null)
				unidad = productoUnidad.getUnidad().getNombre();
			else
				unidad = "VACIA";
			producto.getProductounidads().remove(productoUnidad);
			int o = 1;
			for (Productounidad pu : producto.getProductounidads())
				pu.setOrden(o++);

			presentaMensaje(FacesMessage.SEVERITY_INFO, "SE ELIMINO LA UNIDAD "
					+ unidad);
		} else
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"DEBE TENER AL MENOS UNA UNIDAD VÁLIDA");
	}

	private void inicializar(Producto producto) {
		for (TipoPrecioProducto tipoPrecioProducto : producto
				.getTipoPrecioProductos()) {
			tipoPrecioProducto
					.setValor(redondear(tipoPrecioProducto.getValor()));
		}

		if (producto.getPrecio() != null)
			producto.setPrecio(redondear(producto.getPrecio()));
		if (producto.getIce() != null)
			producto.setIce(redondear(producto.getIce()));
	}

	public void insertar(Producto producto,
			List<TablaPrecios> listaPrecioProductos) {
		producto = nombre(producto);
		producto.setCodigo2(producto.getCodigo1());
		producto.setActivo(true);

		Set<ConstraintViolation<Producto>> violationsProducto = validator
				.validate(producto);

		if (violationsProducto.size() > 0)
			for (ConstraintViolation<Producto> cv : violationsProducto)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
		else if (producto.getPrecio().compareTo(new BigDecimal("0")) == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"INGRESE EL PRECIO COSTO");
		else if (comprobarUnidadesVacias(producto))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE UNIDADES VACIAS O CON VALOR CERO");
		else if (producto.getGrupo().getGrupoid() == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO, "ESCOJA UN GRUPO");
		else if (comprobarCaracteristicasVacias(producto))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"INGRESE UN VALOR EN UNA DE LAS CARACTERISTICAS IMPRIMIBLES");
		else if (comprobarPreciosVacias(listaPrecioProductos))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE TIPOS DE PRECIOS VACIOS O NO A ESCOGIDO EL PVP");
		else if (productoDao.comprobarIndices(Producto.class, "ean",
				producto.getEan(), String.valueOf(producto.getProductoid())))
			presentaMensaje(FacesMessage.SEVERITY_INFO, "EL EAN YA EXISTE",
					"error", false);
		else if (productoDao
				.comprobarIndices(Producto.class, "codigo1",
						producto.getCodigo1(),
						String.valueOf(producto.getProductoid())))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"EL CÓDIGO 1 YA EXISTE", "error", false);
		else if (productoDao.comprobarIndices(Producto.class, "nombre",
				producto.getNombre(), String.valueOf(producto.getProductoid())))
			presentaMensaje(FacesMessage.SEVERITY_INFO, "EL NOMBRE YA EXISTE",
					"error", false);
		else {
			producto.setTipoPrecioProductos(new ArrayList<TipoPrecioProducto>());
			for (TablaPrecios tablaPrecios : listaPrecioProductos)
				if (tablaPrecios.getTipoPrecioProducto()
						.getPorcentajepreciofijo()) {
					tablaPrecios.getTipoPrecioProducto().setValor(
							tablaPrecios.getPorcentaje());
					producto.addTipoPrecioProducto(tablaPrecios
							.getTipoPrecioProducto());
				} else {
					tablaPrecios.getTipoPrecioProducto().setValor(
							tablaPrecios.getPrecio());
					producto.addTipoPrecioProducto(tablaPrecios
							.getTipoPrecioProducto());
				}

			int c = 1;
			for (Productounidad pu : producto.getProductounidads())
				pu.setOrden(c++);
			c = 1;
			for (TipoPrecioProducto tp : producto.getTipoPrecioProductos())
				tp.setOrden(c++);

			productoDao.insertar(producto);
			presentaMensaje(FacesMessage.SEVERITY_INFO, "INSERTÓ PRODUCTO: "
					+ producto.getNombre(), "error", true);
		}
	}

	public Producto nombre(Producto producto) {
		String nombre = "";
		String nombreImprimir = "";

		for (Productocaracteristica iterable : producto
				.getProductocaracteristicas()) {

			if (iterable.getImprimir())
				nombreImprimir = nombreImprimir + iterable.getValor() + " ";
			if (iterable.getValor() != null)
				nombre = nombre + iterable.getCaracteristica().getNombre()
						+ ":" + iterable.getValor() + " ";

		}
		producto.setNombre(nombre.substring(0, nombre.length() - 1));
		producto.setNombreimprimir(nombreImprimir.substring(0,
				nombreImprimir.length() - 1));
		return producto;
	}

	public List<Producto> obtener() {
		List<Producto> list = productoDao.obtenerPorHql(
				"select distinct p from Producto p "
						+ "inner join fetch p.productocaracteristicas "
						+ "inner join fetch p.productounidads "
						+ "inner join fetch p.tipoPrecioProductos "
						+ "order by p.nombreimprimir", new Object[] {});
		for (Producto producto : list)
			inicializar(producto);
		return list;
	}

	public List<Producto> obtener(String criterioBusqueda,
			Integer criterioBusquedaGrupo) {
		List<Producto> list = null;
		criterioBusqueda = criterioBusqueda.toUpperCase();

		if (criterioBusqueda.compareToIgnoreCase("") == 0
				&& criterioBusquedaGrupo == 0)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE UN CRITERIO DE BÚSQUEDA");
		else if (criterioBusquedaGrupo == 0 && criterioBusqueda.length() < 3)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE MINIMO 3 CARACTERES");
		else {
			if (criterioBusquedaGrupo != 0
					&& criterioBusqueda.compareToIgnoreCase("") != 0)
				list = productoDao
						.obtenerPorHql(
								"select distinct p from Producto p inner join p.grupo g "
										+ "inner join fetch p.productocaracteristicas "
										+ "inner join fetch p.productounidads "
										+ "inner join fetch p.tipoPrecioProductos "
										+ "where g.grupoid=?1 "
										+ "and (p.nombre like ?2 or p.ean like ?2 or p.codigo1 like ?2 or p.codigo2 like ?2) "
										+ "order by p.nombreimprimir",
								new Object[] { criterioBusquedaGrupo,
										"%" + criterioBusqueda + "%" });
			else if (criterioBusqueda.compareToIgnoreCase("") != 0)
				list = productoDao
						.obtenerPorHql(
								"select distinct p from Producto p inner join p.grupo g "
										+ "inner join fetch p.productocaracteristicas "
										+ "inner join fetch p.productounidads "
										+ "inner join fetch p.tipoPrecioProductos "
										+ "where p.nombre like ?1 or p.ean like ?1 or p.codigo1 like ?1 or p.codigo2 like ?1 "
										+ "order by p.nombre",
								new Object[] { "%" + criterioBusqueda + "%" });
			else if (criterioBusquedaGrupo != 0)
				list = productoDao.obtenerPorHql(
						"select distinct p from Producto p inner join p.grupo g "
								+ "inner join fetch p.productocaracteristicas "
								+ "inner join fetch p.productounidads "
								+ "inner join fetch p.tipoPrecioProductos "
								+ "where g.grupoid=?1 order by p.nombre",
						new Object[] { criterioBusquedaGrupo });

			if (list.isEmpty())
				presentaMensaje(FacesMessage.SEVERITY_WARN,
						"NO SE ENCONTRO NINGUN RESULTADO");
			else
				for (Producto producto : list)
					inicializar(producto);
		}
		return list;
	}

	public List<ControlInventarioReporte> obtenerControlInventario(
			Integer bodegaId) {
		@SuppressWarnings("unchecked")
		List<ControlInventarioReporte> lista = (List<ControlInventarioReporte>) productoDao
				.obtenerPorSql1(
						"select distinct p.productoid as id, p.ean as ean, p.nombreimprimir as nombre, 0.00 as stock "
								+ "from invfac.producto p "
								+ "inner join invfac.kardex k on (k.productoid=p.productoid) "
								+ "inner join invfac.bodega b on (b.bodegaid=k.bodegaid) "
								+ "where b.bodegaid="
								+ bodegaId
								+ " order by p.nombreimprimir",
						ControlInventarioReporte.class);
		return lista;
	}

	public List<Producto> obtenerParaBusqueda(String criterioProductoBusqueda) {
		criterioProductoBusqueda = criterioProductoBusqueda.toUpperCase();
		List<Producto> list = new ArrayList<Producto>();
		if (criterioProductoBusqueda.length() >= 0
				&& criterioProductoBusqueda.length() < 3)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE MAS DE 2 CARACTERES");
		else {
			list = productoDao
					.obtenerPorHql(
							"select p from Producto p where (p.nombre like ?1 or p.ean like ?1 or p.codigo1 like ?1 or p.codigo2 like ?1) and p.activo=true",
							new Object[] { "%" + criterioProductoBusqueda + "%" });
			if (list.isEmpty())
				presentaMensaje(FacesMessage.SEVERITY_ERROR,
						"NO SE ENCONTRO NINGUNA COINCIDENCIA");
		}
		return list;
	}

	public List<Producto> obtenerPorBodega(Integer bodegaId) {
		List<Producto> list = productoDao
				.obtenerPorHql(
						"select p from Producto p "
								+ "inner join p.kardexs k inner join k.bodega b "
								+ "where b.bodegaid=?1 and p.activo=true and k.activo=true "
								+ "order by p.nombreimprimir",
						new Object[] { bodegaId });
		for (Producto producto : list)
			inicializar(producto);

		return list;
	}

	public List<Producto> obtenerPorBodegaAndGrupo(Integer bodegaId,
			Integer grupoId) {
		List<Producto> list = productoDao.obtenerPorHql(
				"select distinct p from Producto p inner join p.grupo g "
						+ "inner join p.kardexs k inner join k.bodega b "
						+ "where b.bodegaid=?1 "
						+ "and g.grupoid=?2 and p.activo=true "
						+ "order by p.nombreimprimir", new Object[] { bodegaId,
						grupoId });
		for (Producto producto : list)
			inicializar(producto);

		return list;
	}

	public List<BodegaProducto> obtenerPorBodegaProducto(String ean) {
		List<BodegaProducto> listaBodegaProductos = new ArrayList<BodegaProducto>();
		List<Bodega> listaBodegas = bodegaService.obtenerActivos();
		for (Bodega bodega : listaBodegas) {
			Kardex kardex = kardexService.obtenerSaldoActual(ean,
					bodega.getBodegaid());

			if (kardex != null)
				listaBodegaProductos.add(new BodegaProducto(bodega.getNombre(),
						kardex.getCantidad()));
		}
		return listaBodegaProductos;
	}

	public Producto obtenerPorCodigo(String codigo) {
		Producto p = productoDao.obtenerPorHql(
				"select distinct p from Producto p "
						+ "inner join fetch p.productocaracteristicas "
						+ "inner join fetch p.productounidads "
						+ "inner join fetch p.tipoPrecioProductos "
						+ "where p.codigo1=?1", new Object[] { codigo }).get(0);
		inicializar(p);
		return p;
	}

	public Producto obtenerPorCodigosAndLocal(Integer localId, String codigo) {
		Producto p = productoDao
				.obtenerPorHql(
						"select distinct p from Producto p "
								+ "inner join p.kardexs k inner join k.bodega b "
								+ "inner join b.bodegalocals bl inner join bl.local l "
								+ "inner join fetch p.productocaracteristicas "
								+ "inner join fetch p.productounidads "
								+ "inner join fetch p.tipoPrecioProductos "
								+ "where l.localid=?1 "
								+ "and (p.ean like ?2 or p.codigo1 like ?2 or p.codigo2 like ?2) "
								+ "and p.activo=true",
						new Object[] { localId, "%" + codigo + "%" }).get(0);
		inicializar(p);
		return p;
	}

	public Producto obtenerPorEan(String ean) {
		Producto p = productoDao.obtenerPorHql(
				"select distinct p from Producto p "
						+ "inner join fetch p.productocaracteristicas "
						+ "inner join fetch p.productounidads "
						+ "inner join fetch p.tipoPrecioProductos "
						+ "where p.ean=?1", new Object[] { ean }).get(0);
		if (p != null)
			inicializar(p);
		return p;
	}

	public List<Producto> obtenerPorEanAndBodega(String ean, Integer bodegaId) {
		List<Producto> list = productoDao
				.obtenerPorHql(
						"select distinct p from Producto p "
								+ "inner join p.kardexs k inner join k.bodega b "
								+ "where (p.nombre like ?1 or p.ean like ?1 or p.codigo1 like ?1 or p.codigo2 like ?1) and b.bodegaid=?2  and p.activo=true",
						new Object[] { "%" + ean + "%", bodegaId });
		for (Producto producto : list)
			inicializar(producto);
		return list;
	}

	public List<Producto> obtenerPorKardexInicial(Integer bodegaId) {
		List<Producto> list = productoDao
				.obtenerPorHql(
						"select distinct p from Producto p left join p.productosbodegas pb left join pb.bodega b where (pb.bodega.bodegaid!=?1 or size(p.productosbodegas)=0) and p.activo=true",
						new Object[] { bodegaId });
		for (Producto producto : list) {
			inicializar(producto);
		}
		return list;
	}

	public List<Producto> obtenerPorLocal(String criterioProductoBusqueda,
			Integer localId) {
		criterioProductoBusqueda = criterioProductoBusqueda.toUpperCase();
		List<Producto> list = new ArrayList<Producto>();
		if (criterioProductoBusqueda.length() >= 0
				&& criterioProductoBusqueda.length() <= 3)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE MAS DE 3 CARACTERES");
		else {
			list = productoDao
					.obtenerPorHql(
							"select distinct p from Producto p "
									+ "inner join p.kardexs k inner join k.bodega b "
									+ "inner join b.bodegalocals bl inner join bl.local l "
									+ "where l.localid=?1 "
									+ "and (p.nombre like ?2 or p.ean like ?2 or p.codigo1 like ?2 or p.codigo2 like ?2) "
									+ "and p.activo=true", new Object[] {
									localId,
									"%" + criterioProductoBusqueda + "%" });
			if (list.isEmpty())
				presentaMensaje(FacesMessage.SEVERITY_WARN,
						"NO SE ENCONTRO NINGUN RESULTADO");
		}
		return list;
	}

	public Producto obtenerPorProductoId(Long productoId) {
		Producto p = productoDao.obtenerPorHql(
				"select distinct p from Producto p "
						+ "inner join fetch p.productocaracteristicas "
						+ "inner join fetch p.productounidads "
						+ "inner join fetch p.tipoPrecioProductos "
						+ "where p.productoid=?1", new Object[] { productoId })
				.get(0);
		inicializar(p);
		return p;
	}

	public Integer obtenerPvpPorProducto(List<TipoPrecioProducto> list) {
		for (TipoPrecioProducto tpp : list)
			if (tpp.getPvp())
				return tpp.getTipoprecioproductoid();

		return null;
	}

	public StreamedContent generarCodigo(Producto producto, String codigoTipo) {
		String codigo = null;
		StreamedContent codigoBarra = null;
		if (producto != null && producto.getProductoid() != null) {
			if (codigoTipo.compareTo("ean") == 0) {
				codigo = producto.getEan();
			} else if (codigoTipo.compareTo("codigo1") == 0) {
				codigo = producto.getCodigo1();
			} else if (codigoTipo.compareTo("codigo2") == 0) {
				codigo = producto.getCodigo2();
			}
			try {
				File codigoBarraFile = new File("dynamiccodigoBarra");
				BarcodeImageHandler.saveJPEG(
						BarcodeFactory.createCode128(codigo), codigoBarraFile);
				codigoBarra = new DefaultStreamedContent(new FileInputStream(
						codigoBarraFile), "image/jpeg");
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else
			presentaMensaje(FacesMessage.SEVERITY_ERROR, "ESCOJA UN PRODUCTO");
		return codigoBarra;
	}

	public TipoPrecioProducto obtenerValorPvp(List<TipoPrecioProducto> list) {
		for (TipoPrecioProducto tpp : list)
			if (tpp.getPvp())
				return tpp;
		return null;
	}
}